package gov.tax.rti.ext.bdf2.jdbc;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.bstek.bdf2.core.orm.jdbc.JdbcDao;

public class JdbcDaoSupport<T, PK extends Serializable> extends JdbcDao{
	
	private static final Log logger = LogFactory.getLog(JdbcDaoSupport.class);
	
    public JdbcTemplate getJdbcTemplate(String dataSourceName)
    {
        return super.getJdbcTemplate(getDataSourceName(dataSourceName));
    }

    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(String dataSourceName)
    {
    	return super.getNamedParameterJdbcTemplate(getDataSourceName(dataSourceName));
    }
    
	protected Class<T> entityType = getEntityType();
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected Class<T> getEntityType() {
		Class cl = getClass();
		Class<T> resultType = null;
		Type superType = cl.getGenericSuperclass();

		if (superType instanceof ParameterizedType) {
			Type[] paramTypes = ((ParameterizedType) superType)
					.getActualTypeArguments();
			if (paramTypes.length > 0) {
				try{
					resultType = (Class<T>) paramTypes[0];
				}catch(ClassCastException e){
					logger.warn("Can not determine EntityType for class ["
							+ e.getMessage() + "].");
				}
			} else {
				logger.warn("Can not determine EntityType for class ["
						+ cl.getSimpleName() + "].");
			}
		} else {
			logger.warn("[" + cl.getSimpleName()
					+ "] is not a parameterized type.");
		}
		return resultType;
	}
    
    protected ObjRowMapper<T> getObjRowMapper(){
    	return new ObjRowMapper<T>(entityType);
    }
    
    @SuppressWarnings("unchecked")
	protected <I> ObjRowMapper<I> getIObjRowMapper(Class<I> iType){
    	return new ObjRowMapper<I>(iType, (Class<? extends I>) entityType);
    }
    
    protected <E> ObjRowMapper<E> getObjRowMapper(Class<E> entityType){
    	return new ObjRowMapper<E>(entityType);
    }
    
    protected <I> ObjRowMapper<I> getIObjRowMapper(Class<I> iType, Class<? extends I> entityType){
    	return new ObjRowMapper<I>(iType, entityType);
    }
    
    /**
	 * 返回实体类（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @return T 实体类
	 */
	protected T queryObj(String sql) {
    	return this.getJdbcTemplate().queryForObject(sql, getObjRowMapper());
	}
    
	/**
	 * 返回实体类
	 * 
	 * @param sql
	 * @param entityType 返回对象实体类E
	 * @return E 实体类
	 */
	protected <E> E queryObj(String sql, Class<E> entityType) {
    	return this.getJdbcTemplate().queryForObject(sql, getObjRowMapper(entityType));
	}
	
	/**
	 * 返回实体类（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param args 参数
	 * @return T 实体类
	 */
	protected T queryObj(String sql, Object[] args) {
    	return this.getJdbcTemplate().queryForObject(sql, args, getObjRowMapper());
	}
    
	/**
	 * 返回实体类
	 * 
	 * @param sql
	 * @param args 参数
	 * @param entityType 返回对象实体类E
	 * @return E 实体类
	 */
	protected <E> E queryObj(String sql, Object[] args, Class<E> entityType) {
    	return this.getJdbcTemplate().queryForObject(sql, args, getObjRowMapper(entityType));
	}
    
	/**
	 * 返回实体类（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param paras 参数
	 * @return T 实体类
	 */
	protected T queryObj(String sql, Map<String, Object> paras) {
    	return this.getNamedParameterJdbcTemplate().queryForObject(sql, paras, getObjRowMapper());
	}
    
	/**
	 * 返回实体类
	 * 
	 * @param sql
	 * @param paras 参数
	 * @param entityType 返回对象实体类E
	 * @return E 实体类
	 */
	protected <E> E queryObj(String sql, Map<String, Object> paras, Class<E> entityType) {
    	return this.getNamedParameterJdbcTemplate().queryForObject(sql, paras, getObjRowMapper(entityType));
	}
    
	/**
	 * 返回实体类集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @return List<T> 实体类集合
	 */
	protected List<T> queryObjs(String sql) {
    	return this.getJdbcTemplate().query(sql, getObjRowMapper());
	}
    
	/**
	 * 返回实体类集合
	 * 
	 * @param sql
	 * @param entityType 返回对象实体类
	 * @return List<E> 实体类集合
	 */
	protected <E> List<E> queryObjs(String sql, Class<E> entityType) {
    	return this.getJdbcTemplate().query(sql, getObjRowMapper(entityType));
	}
    
	/**
	 * 返回实体类集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param args 参数
	 * @return List<T> 实体类集合
	 */
	protected List<T> queryObjs(String sql, Object[] args) {
    	return this.getJdbcTemplate().query(sql, args, getObjRowMapper());
	}
    
	/**
	 * 返回实体类集合
	 * 
	 * @param sql
	 * @param args 参数
	 * @param entityType 返回对象实体类
	 * @return List<E> 实体类集合
	 */
	protected <E> List<E> queryObjs(String sql, Object[] args, Class<E> entityType) {
    	return this.getJdbcTemplate().query(sql, args, getObjRowMapper(entityType));
	}
    
	/**
	 * 返回实体类集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param paras 参数
	 * @return List<T> 实体类集合
	 */
	protected List<T> queryObjs(String sql, Map<String, Object> paras) {
    	return this.getNamedParameterJdbcTemplate().query(sql, paras, getObjRowMapper());
	}
    
	/**
	 * 返回实体类集合
	 * 
	 * @param sql
	 * @param paras 参数
	 * @param entityType 返回对象实体类
	 * @return List<E> 实体类集合
	 */
	protected <E> List<E> queryObjs(String sql, Map<String, Object> paras, Class<E> entityType) {
    	return this.getNamedParameterJdbcTemplate().query(sql, paras, getObjRowMapper(entityType));
	}
	
	/**
	 * 返回接口类型集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param iType 返回对象接口（子dao类设定的T实体类的接口）
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Class<I> iType) {
    	return this.getJdbcTemplate().query(sql, getIObjRowMapper(iType));
	}
	
	/**
	 * 返回接口类型集合
	 * 
	 * @param sql
	 * @param iType 返回对象接口
	 * @param entityType 返回对象实体类
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Class<I> iType, Class<? extends I> entityType) {
    	return this.getJdbcTemplate().query(sql, getIObjRowMapper(iType, entityType));
	}
	
	/**
	 * 返回接口类型集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param args 参数
	 * @param iType 返回对象接口（子dao类设定的T实体类的接口）
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Object[] args, Class<I> iType) {
    	return this.getJdbcTemplate().query(sql, args, getIObjRowMapper(iType));
	}
    
	/**
	 * 返回接口类型集合
	 * 
	 * @param sql
	 * @param args 参数
	 * @param iType 返回对象接口
	 * @param entityType 返回对象实体类
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Object[] args, Class<I> iType, Class<? extends I> entityType) {
    	return this.getJdbcTemplate().query(sql, args, getIObjRowMapper(iType, entityType));
	}
    
	/**
	 * 返回接口类型集合（根据子dao类设定的T实体类）
	 * 
	 * @param sql
	 * @param paras 参数
	 * @param iType 返回对象接口（子dao类设定的T实体类的接口）
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Map<String, Object> paras, Class<I> iType) {
    	return this.getNamedParameterJdbcTemplate().query(sql, paras, getIObjRowMapper(iType));
	}
    
	/**
	 * 返回接口类型集合
	 * 
	 * @param sql
	 * @param paras 参数
	 * @param iType 返回对象接口
	 * @param entityType 返回对象实体类
	 * @return List<I> 接口集合
	 */
	protected <I> List<I> queryIObjs(String sql, Map<String, Object> paras, Class<I> iType, Class<? extends I> entityType) {
    	return this.getNamedParameterJdbcTemplate().query(sql, paras, getIObjRowMapper(iType, entityType));
	}

}